#pragma once
#include "MarkerMgr.h"

class StatusMgr : protected IEntityMgr {
public:
	static auto get() {
		static auto instance = new StatusMgr;
		return instance;
	}

	/** @note do not check if current status is the same as last one, because road lines change every frame. */
	void updateEntities() override {
		if (Proj::isSQ() || Proj::isSSQK()) {
			updateSQStatus();
			return;
		}

		const auto& status = Cache::status();
		MarkerMgr::get()->update(MarkerType::DCLC);
		MarkerMgr::get()->update(MarkerType::ALC);
		MarkerMgr::get()->update(MarkerType::LDW);
		MarkerMgr::get()->update(MarkerType::ACC_TG);
		MarkerMgr::get()->update(MarkerType::TailLamp);
	}

	void clear() override {
		if (Proj::isSQ() || Proj::isSSQK())
			Cache::clearSQStatus();
		else
			Cache::clearStatus();
		updateEntities();
	}

private:
	StatusMgr() = default;

	void updateSQStatus() {
		static bool startAlcCountDown = false;
		static int alcOFFFrameCnt = 0;
		static float lastRC0 = -1;
		const auto& eqR = Cache::lineArg(LineTag::R).eq;
		if (eqR.isValid()) {
			float curRC0 = eqR.C[0];
			if (startAlcCountDown) {
				Cache::updateSQ_ALC(sq::ALC::Off);
				if (--alcOFFFrameCnt <= 0) {
					startAlcCountDown = false;
					LogI << "After 3s, ALC signal recovered now!";
				}
			} else {
				const auto& status = Cache::sqStatus();
				if (status.alc != sq::ALC::INVALID && status.alc != sq::ALC::Off) {
					if (lastRC0 != -1 && std::abs(curRC0 - lastRC0) > 2.0) {// change lane
						Cache::updateSQ_ALC(sq::ALC::Off);
						startAlcCountDown = true;
						alcOFFFrameCnt = 180;// 3s, 60FPS = 1s
						LogI << "Lane Changed! forbid ALC signal for 3s...";
					}
				}
			}
			lastRC0 = curRC0;
		}

		const auto& status = Cache::sqStatus();
		sq::ALC alc = status.alc;// priority higher than NOA

		if (alc == sq::ALC::Left) Cache::updateDCLC(DCLC::ToLeft);
		else if (alc == sq::ALC::Right) Cache::updateDCLC(DCLC::ToRight);
		else if (status.noa == sq::NOA::On) Cache::updateDCLC(DCLC::Mid);
		else Cache::updateDCLC(DCLC::Off);

		MarkerMgr::get()->update(MarkerType::SQ_ALC);
		MarkerMgr::get()->update(MarkerType::DCLC);
	}
};